feat: add Premium Geo DB addon to project settings#2981
Conversation
Adds a Premium Geo DB section to the project settings page so users can enable and disable the premium geolocation addon per-project on cloud. The section supports the full addon lifecycle: - Upgrade prompt when the current plan does not support the addon - Enable flow with optional 3DS payment authentication - Pending state with cancel & retry option - Active state with disable action - Scheduled-for-removal state with re-enable action Uses the new project-scoped SDK methods: listAddons, createPremiumGeoDBAddon, and deleteAddon. Bumps the @appwrite.io/console SDK pin accordingly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR adds a Premium Geo DB addon section to the project settings page, implementing the full enable/disable/pending/scheduled-for-removal lifecycle mirroring the existing BAA pattern at the org level. It also bumps the
Confidence Score: 3/5Multiple addon lifecycle flows leave users in irrecoverable states or with silent failures; hold until the pending-cancel gap and the 3DS handling issues are resolved. The pending-payment state has no cancel action, so a user whose payment confirmation keeps failing is permanently blocked from enabling or disabling the addon without support intervention.
Important Files Changed
Reviews (18): Last reviewed commit: "fix(settings): handle 3DS redirect + rep..." | Re-trigger Greptile |
Mirrors the BAA addon UX by fetching the addon price via organizations.getAddonPrice(Addon.Premiumgeodb) from the settings page loader, passing it through to the Premium Geo DB card and enable modal, and rendering the monthly/prorated breakdown with formatCurrency alongside the Enable CTA. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…name - Each project row in the organization billing breakdown now iterates its resources for addon_* entries (amount > 0) and renders them as child rows (e.g. Premium Geo DB under the project it was enabled on). The backend already filters project-scoped addons out of the team-level resources response, so the org "Addons" section shows only org-scoped addons (BAA, premiumGeoDBOrg) while project-scoped ones surface where they belong. - Org-level addon labels now read addon.name from the UsageResource payload that the getAggregation endpoint populates from billingAddons config. Dropped the hard-coded billingAddonNames map so new addons surface with their proper name without a console update. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…geo-db-addon # Conflicts: # bun.lock # package.json # src/routes/(console)/project-[region]-[project]/settings/+page.svelte
…geo-db-addon # Conflicts: # bun.lock # package.json
…DK methods" This reverts commit 304142c.
…geo-db-addon # Conflicts: # src/routes/(console)/project-[region]-[project]/settings/+page.svelte # src/routes/(console)/project-[region]-[project]/settings/+page.ts
| ...resources | ||
| .filter((r) => r.resourceId?.startsWith('addon_') && (r.amount ?? 0) > 0) | ||
| .map((addon) => | ||
| createRow({ | ||
| id: `addon-${addon.resourceId}`, | ||
| label: addon.name || addon.resourceId, | ||
| resource: addon, | ||
| usageFormatter: ({ value }) => formatNum(value), | ||
| priceFormatter: ({ amount }) => formatCurrency(amount), | ||
| includeProgress: false | ||
| }) | ||
| ), |
There was a problem hiding this comment.
Possible double-counting of addon charges in plan summary
The top-level addons section (line 252–275) already creates a billing row for every addon_-prefixed resource found in currentAggregation.resources. If the billing API also surfaces those same addon resources inside projectData.resources (the per-project breakdown), each project-scoped addon (e.g. Premium Geo DB) will appear as both a top-level line item and a child row — showing the same charge twice to the user.
Before shipping, confirm whether the cloud billing API places project-level addon charges exclusively in breakdown[].resources (making the top-level filter skip them) or in both places. If the former, this code is correct; if the latter, the top-level addons filter needs to exclude resources that are already accounted for at the project level (or vice-versa).
…geo-db-addon # Conflicts: # bun.lock # package.json
…geo-db-addon # Conflicts: # bun.lock # package.json
…h for premium geoDB Two missing pieces vs the BAA addon flow: 1. After Stripe redirects back from 3DS with ?type=confirm-addon&addonId=..., the page didn't read the query params or call the confirmations endpoint, so the addon stayed pending forever. Port the onMount handler from BAA.svelte. 2. The pending-state action was "Cancel & retry" which deleted the addon and forced a fresh 3DS flow. That's wasteful when the payment just needs a server-side status sync. Replace with "Refresh" — calls the confirmations endpoint, which live-queries Stripe and activates the addon if the PaymentIntent has transitioned to succeeded. Backend cleans up on 402.
| {:else if isPending} | ||
| <div class="u-flex u-cross-center u-gap-8 u-margin-block-start-8"> | ||
| <Badge variant="secondary" type="warning" content="Payment pending" /> | ||
| </div> | ||
| <p class="text u-margin-block-start-8"> | ||
| A payment is awaiting confirmation. If you've completed authentication, click | ||
| refresh to check the payment status. | ||
| </p> | ||
| <Button | ||
| secondary | ||
| class="u-margin-block-start-16" | ||
| disabled={refreshing} | ||
| on:click={handleRefresh}> | ||
| <span class="text">Refresh</span> | ||
| </Button> |
There was a problem hiding this comment.
No escape route for stuck pending addons
When the addon is in pending state the user only sees a "Refresh" button. If confirmAddonPayment keeps returning an error (e.g., persistent 402 or a network issue), the user is trapped: the "Enable" CTA is hidden (the branch falls to isPending first), and there is no way to cancel the pending payment and start over. The PR description's own test plan calls this out as "Pending state with cancel & retry option (if payment was interrupted)", but no cancel action is wired up.
A "Cancel" button that calls deleteAddon (same SDK method used by the disable modal) should be added next to "Refresh" so users can abort a stuck pending payment and re-enter the enable flow from a clean state.
Summary
Adds a Premium Geo DB section to the project settings page so users can enable and disable the premium geolocation addon per-project on cloud.
The section supports the full addon lifecycle, mirroring the BAA pattern at the organization level:
Uses the new project-scoped SDK methods shipped with the cloud update:
listAddons,createPremiumGeoDBAddon, anddeleteAddon. Bumps the@appwrite.io/consoleSDK pin accordingly.Test plan
🤖 Generated with Claude Code